package org.example.annotation.log;


import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.example.annotation.properties.AnnotationProperties;
import org.example.annotation.service.ILogHandleService;
import org.example.system.common.bean.LogTrace;
import org.example.system.common.utils.AddrUtil;
import org.example.system.common.utils.JoeDevUtils;
import org.example.system.common.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * 日志注解实现
 * @author joey
 */
@Component
@Aspect
@Slf4j
public class JoeLogAspect {
    @Resource
    AnnotationProperties annotationProperties;
    @Resource
    ILogHandleService logHandleService;

    @Pointcut("@annotation(org.example.annotation.log.JoeLog) " +
            "|| execution(public * org.example..*Controller.*(..))")
    public void handle() {}

    @Around("handle()")
    public Object action(ProceedingJoinPoint joinPoint) throws Throwable {
        if(logHandleService == null){
            return joinPoint.proceed();
        }
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        //是否开启日志追踪
        if(annotationProperties.getEnabled()){
            JoeLogIgnore joeLogIgnore = signature.getMethod().getAnnotation(JoeLogIgnore.class);
            if(joeLogIgnore!=null){
                return joinPoint.proceed();
            }
            LogTrace traceLog = new LogTrace();
            Object result = null;
            long startTime = System.currentTimeMillis();
            try {
                result = joinPoint.proceed();
            }catch (Throwable e){
                traceLog.setSuccess(false);
                traceLog.setException(JoeDevUtils.limitStr(e.getMessage(),1024));
                throw new Throwable(e);
            }finally {
                long endTime = System.currentTimeMillis();
                ApiOperation apiOperation = signature.getMethod().getAnnotation(ApiOperation.class);
                if(apiOperation!=null){
                    traceLog.setName(apiOperation.value());
                }
                traceLog.setTraceId(JwtUtils.getTraceId());
                traceLog.setIp(AddrUtil.getLocalAddr());
                traceLog.setDuration(endTime-startTime);
                traceLog.setClassName(signature.getDeclaringType().getName());
                traceLog.setMethodName(signature.getName());
                traceLog.setParamContent(JoeDevUtils.limitStr(JoeDevUtils.toJSONString(joinPoint.getArgs()),1024));
                traceLog.setResultContent(JoeDevUtils.limitStr(JoeDevUtils.toJSONString(result),1024));
                traceLog.setCreateBy(JwtUtils.getCurrentUserIdNoException());
                traceLog.setUrl(JoeDevUtils.getRequestURI());
                traceLog.setCreateTime(LocalDateTime.now());
                logHandleService.pushQueue(traceLog);
            }
            return result;
        }else {
            return joinPoint.proceed();
        }
    }
}
